Passed
Push — master ( 9616b1...afd77f )
by Rafael S.
55s
created

BitDepthFunctions.intToFloat   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
/*!
2
 * bitdepth
3
 * Change the bit depth of samples to and from 8, 16, 24, 32 & 64-bit.
4
 * Copyright (c) 2017 Rafael da Silva Rocha.
5
 * https://github.com/rochars/bitdepth
6
 *
7
 */
8
9
const f64f32 = new Float32Array(1);
10
11
/**
12
 * Max number of different values for each bit depth.
13
 * @enum {number}
14
 */
15
const BitDepthMaxValues = {
16
    "8": 256,
17
    "16": 65536,
18
    "24": 16777216,
19
    "32": 4294967296,
20
    "32f": 1,
21
    "64": 1
22
};
23
24
/**
25
 * Functions to change the bit depth of a sample.
26
 */
27
const BitDepthFunctions = {
28
29
    /**
30
     * Change the bit depth from int to int.
31
     * @param {number} sample The sample.
32
     * @param {Object} args Data about the original and target bit depths.
33
     * @return {number}
34
     */
35
    intToInt(sample, args) {
36
        if (sample > 0) {
37
            sample = parseInt((sample / (args.old - 1)) * args.new - 1, 10);
38
        } else {
39
            sample = parseInt((sample / args.old) * args.new, 10);
40
        }
41
        return sample;
42
    },
43
44
    /**
45
     * Change the bit depth from float to int.
46
     * @param {number} sample The sample.
47
     * @param {Object} args Data about the original and target bit depths.
48
     * @return {number}
49
     */
50
    floatToInt(sample, args) {
51
        if (sample > 0) {
52
            sample = sample * (args.new - 1);
53
        } else {
54
            sample = sample * args.new;
55
        }
56
        return sample;
57
    },
58
59
    /**
60
     * Change the bit depth from int to float.
61
     * @param {number} sample The sample.
62
     * @param {Object} args Data about the original and target bit depths.
63
     * @return {number}
64
     */
65
    intToFloat(sample, args) {
66
        if (sample > 0) {
67
            sample = sample / (args.old - 1);
68
        } else {
69
            sample = sample / args.old;
70
        }
71
        return sample;
72
    },
73
74
    /**
75
     * Change the bit depth from float to float.
76
     * @param {number} sample The sample.
77
     * @param {Object} args Data about the original and target bit depths.
78
     * @return {number}
79
     */
80
    floatToFloat(sample, args) {
81
        if (args.original == "64" && args.target == "32f") {
82
            f64f32[0] = sample;
83
            sample = f64f32[0];
84
        }
85
        return sample;
86
    }
87
};
88
89
/**
90
 * Change the bit depth of the data in a sample array.
91
 * The input array is modified in-place.
92
 * @param {!Array<number>} samples The samples.
93
 * @param {string} originalBitDepth The original bit depth of the data.
94
 *      One of "8", "16", "24", "32", "32f", "64"
95
 * @param {string} targetBitDepth The new bit depth of the data.
96
 *      One of "8", "16", "24", "32", "32f", "64"
97
 */
98
function toBitDepth(samples, originalBitDepth, targetBitDepth) {
99
    validateBitDepths(originalBitDepth, targetBitDepth);
100
    let toFunction = getBitDepthFunction(originalBitDepth, targetBitDepth);
101
    let len = samples.length;
102
    for (let i=0; i<len; i++) {        
103
        samples[i] = sign8Bit(samples[i], originalBitDepth);
104
        samples[i] = toFunction(
105
                samples[i],
106
                {
107
                    "old": BitDepthMaxValues[originalBitDepth] / 2,
108
                    "new": BitDepthMaxValues[targetBitDepth] / 2,
109
                    "original": originalBitDepth,
110
                    "target": targetBitDepth
111
                }
112
            );
113
        samples[i] = unsign8Bit(samples[i], targetBitDepth);
114
    }
115
}
116
117
/**
118
 * Get the function to change the bit depth of a sample.
119
 * @param {string} originalBitDepth The original bit depth of the data.
120
 *      One of "8", "16", "24", "32", "32f", "64"
121
 * @param {string} targetBitDepth The new bit depth of the data.
122
 *      One of "8", "16", "24", "32", "32f", "64"
123
 * @return {Function}
124
 */
125
function getBitDepthFunction(originalBitDepth, targetBitDepth) {
126
    let prefix;
127
    let suffix;
128
    if (["32f", "64"].includes(originalBitDepth)) {
129
        prefix = "float";
130
    } else {
131
        prefix = "int";
132
    }
133
    if (["32f", "64"].includes(targetBitDepth)) {
134
        suffix = "Float";
135
    } else {
136
        suffix = "Int";
137
    }
138
    return BitDepthFunctions[prefix + "To" + suffix];
139
}
140
141
/**
142
 * Sign unsigned 8-bit data.
143
 * @param {number} sample The sample.
144
 * @param {string} originalBitDepth The original bit depth of the data.
145
 *      One of "8", "16", "24", "32", "32f", "64"
146
 * @return {number}
147
 */
148
function sign8Bit(sample, originalBitDepth) {
149
    if (originalBitDepth == "8") {
150
        sample -= 128;
151
    }
152
    return sample;
153
}
154
155
/**
156
 * Unsign signed 8-bit data.
157
 * @param {number} sample The sample.
158
 * @param {string} targetBitDepth The target bit depth of the data.
159
 *      One of "8", "16", "24", "32", "32f", "64"
160
 * @return {number}
161
 */
162
function unsign8Bit(sample, targetBitDepth) {
163
    if (targetBitDepth == "8") {
164
        sample += 128;
165
    }
166
    return sample;
167
}
168
169
/**
170
 * Validate the bit depth.
171
 * @param {string} originalBitDepth The original bit depth.
172
 *     Should be one of "8", "16", "24", "32", "32f", "64".
173
 * @param {string} targetBitDepth The target bit depth.
174
 *     Should be one of "8", "16", "24", "32", "32f", "64".
175
 * @throws {Error} If any argument does not meet the criteria.
176
 * @return {boolean}
177
 */
178
function validateBitDepths(originalBitDepth, targetBitDepth) {
179
    let validBitDepths = ["8", "16", "24", "32", "32f", "64"];
180
    if (validBitDepths.indexOf(originalBitDepth) == -1 ||
181
        validBitDepths.indexOf(targetBitDepth) == -1) {
182
        throw new Error("Invalid bit depth.");
183
    }
184
    return true;
185
}
186
187
module.exports.toBitDepth = toBitDepth;
188
module.exports.BitDepthMaxValues = BitDepthMaxValues;
189